#include "pclviewer.h"
//#include "../src-build/ui_pclviewer.h"
#include "ui_pclviewer.h"

#include <stdio.h>
#include <vector>
#include <string>
#include <sstream>
#include <stdio.h>
#include <fstream>
#include <QFile>
#include <QFileInfo>
#include <QMessageBox>
#include <QKeyEvent>

#include <pcl/console/parse.h>
#include <vtkPlaneSource.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>


#include "rapter/typedefs.h"                    // _2d::, _3d::, Scalar, PointPrimitiveT, PointContainerT
#include "rapter/optimization/segmentation.h"   // segmentCli, orientPoints, patchify

#include "rapter/optimization/candidateGenerator.h"
#include "rapter/optimization/problemSetup.h"
#include "rapter/optimization/solver.h"
#include "rapter/optimization/represent.hpp"
#include "rapter/optimization/merging.h"


#include "rapter/visualization/impl/visualization.hpp"
#include "rapter/typedefs.h"
#include "rapter/primitives/impl/planePrimitive.hpp"
#include "rapter/primitives/impl/linePrimitive.hpp"
#include "pcl/visualization/pcl_visualizer.h"
#include "rapter/processing/impl/angleUtil.hpp" // appendAngles...
#include "rapter/primitives/pointPrimitive.h"



PCLViewer::PCLViewer (QWidget *parent) :
  QMainWindow (parent),
  ui (new Ui::PCLViewer)
{
  ui->setupUi (this);
  this->setWindowTitle ("PCL viewer");

  /********************Original Settings**********************/
  // Setup the cloud pointer
  cloud.reset (new PointCloudT);

  // Set up the QVTK window
  viewer.reset (new pcl::visualization::PCLVisualizer ("viewer", false));
  ui->qvtkWidget->SetRenderWindow (viewer->getRenderWindow ());
  viewer->setupInteractor (ui->qvtkWidget->GetInteractor (), ui->qvtkWidget->GetRenderWindow ());
  ui->qvtkWidget->update ();
  viewer->setBackgroundColor(0.5,0.5,0.5);

  //set the basic info
  //this->basicInfo="<h5>Point Cloud Basic info</h5>";


  /********************Settings**********************/
  for(int i=0;i<3;++i)
      ui->showNormalComboBox->addItem(QString::number(i));


  QStringList list;
  list<<"Segment"<<"Generate"<<"Generate1"<<"Solve"<<"Represent"<<"Merge";
  ui->showSectionComboBox->addItems(list);

}



PCLViewer::~PCLViewer ()
{
  delete ui;
}

void PCLViewer::on_openButton_clicked()
{
    QString strFileName = QFileDialog::getOpenFileName(this,tr("select"),".",tr("open (*.ply *.pcd)"));
    //解决中文路径名问题
    QTextCodec *code = QTextCodec::codecForName("GB2312");
    cloudFileName = code->fromUnicode(strFileName).data();
    //初始化
    if(cloudFileName.length()==0)
        return;

    std::cout<<cloudFileName<<std::endl;

    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz(new pcl::PointCloud<pcl::PointXYZ>);
    //* load the file
    if(cloudFileName.find("ply")!=std::string::npos)
    {
        if (pcl::io::loadPLYFile<pcl::PointXYZ> (cloudFileName, *cloud_xyz) == -1)
        {
            PCL_ERROR ("Couldn't read ply file \n");
            return ;
        }
    }
    else
    {
        if (pcl::io::loadPCDFile<pcl::PointXYZ> (cloudFileName, *cloud_xyz) == -1)
        {
            PCL_ERROR ("Couldn't read pcd file \n");
            return ;
        }
    }

    cloud->points.resize(cloud_xyz->size());
    for (size_t i = 0; i < cloud_xyz->points.size(); i++) {
        cloud->points[i].x = cloud_xyz->points[i].x;
        cloud->points[i].y = cloud_xyz->points[i].y;
        cloud->points[i].z = cloud_xyz->points[i].z;
        cloud->points[i].r=255;
        cloud->points[i].g=255;
        cloud->points[i].b=255;
    }

    //show
    showBasicCloud();
    //add basic info of the point cloud
    //QString num="cloud size:"+cloud->size();
    //this->basicInfo.append(num);


    /********************Enable**********************/
   ui->tabWidget->setEnabled(true);
   ui->saveButton->setEnabled(true);
   ui->qvtkWidget->setEnabled(true);

   /**************Check the Data*********************/
   char* tmp = new char[255];
   int it=0;
   std::string prefix=cloudFileName.substr(0,cloudFileName.find_last_of("/")+1);
   QFileInfo *info;
   do{
       sprintf(tmp,"primitives_merged_it%d.csv",it);
       info = new QFileInfo(QString::fromStdString(prefix + tmp));
       it++;
   }while(info->exists());
   --it;
   if(it>0)
   {
       QStringList list;
       for(int i=0; i<it; ++i)
           list<<QString::number(i);
       this->ui->showItComboBox->addItems(list);
       this->showLog(prefix);
       QMessageBox::information(this,"Note","There exists old Data");
   }

}

void PCLViewer::on_saveButton_clicked()
{

}


void PCLViewer::on_segmentButton_clicked()
{
    rapter::Segmentation::mySegment< rapter::_3d::PrimitiveT
            , rapter::_3d::PrimitiveContainerT
            , rapter::PointPrimitiveT
            , rapter::PointContainerT
            , rapter::Scalar>
            (this->cloudFileName,
             rapter::Scalar(ui->scaleLineEdit->text().toFloat()),
             rapter::Scalar(ui->angleLimitLineEdit->text().toFloat()),
             (int)ui->popLimitLineEdit->text().toFloat(),
             rapter::Scalar(ui->patchDistMultLineEdit->text().toFloat())
             );

    std::string prefix=cloudFileName.substr(0,cloudFileName.find_last_of("/")+1);
    QFile::copy(QString::fromStdString(prefix + "patches.csv"),
                QString::fromStdString(prefix + "segments.csv"));
    QFile::copy(QString::fromStdString(prefix + "points_primitives.csv"),
                QString::fromStdString(prefix + "points_segments.csv"));

    this->currentPrimitive = "segments.csv";
    this->currentAssocitive = "points_segments.csv";
    show3DResults(currentPrimitive,currentAssocitive);



}


void PCLViewer::show3DResults(std::__cxx11::string primitive, std::__cxx11::string associtive)
{
    using namespace rapter::vis;
    std::vector<int> gids;
    std::vector<int> visSizeVector;
    std::vector<int> dids;
    std::vector<int> statuses={-1,1};
    std::vector<float> bg_colours;
    rapter::AnglesT angle_gens ({Scalar(90.)});

    QString str=ui->bgColorLineEdit->text();
    QStringList list=str.split(",");
    for(int i=0;i<list.size();++i)
        bg_colours.push_back(list[i].toFloat());


    std::string prefix=cloudFileName.substr(0,cloudFileName.find_last_of("/")+1);
    std::string cloudName=cloudFileName.substr(cloudFileName.find_last_of("/")+1,cloudFileName.size()-1);

    viewer->removeAllShapes();
    viewer->removeAllPointClouds();

    rapter::vis::myShowCli<rapter::_3d::PrimitiveT>
    (ui->showNormalComboBox->currentIndex(),                            //int     show_normals
     false,                      //bool    show_pids
     ui->popCheckBox->isChecked(),                                      //bool    show_pop
     false,                      //bool    print_angles
     false,                      //bool    paralColours
     false,                      //bool    dir_colours
     ui->hidePointsCheckBox->isChecked(),                               //bool    hide_points
     ui->drawModeLineEdit->text().toInt(),                              //int     draw_mode
     false,                     //bool    no_paral
     true,                      //bool    no_scale_sphere
     false,                     //bool    save_poly
     false,                     //bool    save_hough
     true,                      //bool    show_empty
     gids,                      //std::vector<int> gids
     visSizeVector,             //std::vector<int> visSizeVector
     dids,                      //std::vector<int> dids
     statuses,                  //std::vector<int> statuses
     bg_colours,                //std::vector<float> bg_colours
     false,                     //bool show_spatial
     primitive,                 //std::string primitives_file
     associtive,                //std::string assoc_file
     char(2),                   //char use_tags
     false,                     //bool clusters
     !ui->relationCheckBox->isChecked(),                                //bool dont_show_rels
     ui->idCheckBox->isChecked(),                                       //bool show_ids
     Scalar(ui->scaleLineEdit->text().toFloat()),                       //Scalar scale
     10.e-2,                    //float perfect_angle_limit
     Scalar(1.),                //Scalar  stretch
     Scalar(2.),                //Scalar  hull_alpha
     "",                        //std::string screenshotPath
     "fxxk",                    //std::string title
     ui->popLimitLineEdit->text().toInt(),                                  //int     pop_limit
     prefix,                       //std::string dir
     Scalar(ui->pointSizeLineEdit->text().toInt()),                     //Scalar point_size
     cloudName,                                                     //std::string cloud_file
     angle_gens,                //AnglesT angle_gens
     viewer
     );

}

void PCLViewer::showBasicCloud()
{
    viewer->removeAllShapes();
    viewer->removeAllPointClouds();

    viewer->addPointCloud (cloud, "cloud");
     viewer->setPointCloudRenderingProperties (
                 pcl::visualization::PCL_VISUALIZER_POINT_SIZE,
                 ui->pointSizeLineEdit->text().toInt(),
                 "cloud");
    viewer->resetCamera ();
    ui->qvtkWidget->update ();
}


void PCLViewer::on_OKPushButton_clicked()
{
    show3DResults(this->currentPrimitive, this->currentAssocitive);
}


void PCLViewer::on_computePushButton_clicked()
{
    this->workthread = new workThread(
                this->cloudFileName,
                ui->itLineEdit->text().toInt(),
                ui->scaleLineEdit->text().toFloat(),
                ui->angleLimitLineEdit->text().toFloat(),
                ui->popLimitLineEdit->text().toInt(),
                ui->verboseCheckBox->isChecked(),
                ui->noParaCheckBox->isChecked(),
                /*************generate******************/
                ui->smallThreshMultLineEdit->text().toFloat(),
                ui->angleLimitDivisorLineEdit->text().toFloat(),
                ui->patchDistMultLineEdit->text().toFloat(),
                ui->safeModeCheckBox->isChecked(),
                ui->keepSinglesGheckBox->isChecked(),
                ui->allowPromoteCheckBox->isChecked(),
                ui->adoptChangedGheckBox->isChecked(),
                ui->tripleSafeCheckBox->isChecked(),
                /****************Formulate***************/
                ui->dataLineEdit->text().toFloat(),
                ui->pwLineEdit->text().toFloat(),
                ui->collaoseThreshDegLineEdit->text().toFloat(),
                /****************Merge*******************/
                ui->adoptLineEdit->text().toInt()
                );
    /*****************Connect Signals of show ********/
    connect(workthread,SIGNAL(sendIt(int)),this,SLOT(showIt(int)));


    this->workthread->start(QThread::LowestPriority);
}

void PCLViewer::showIt(int it)
{
    ui->showItComboBox->addItem(QString::number(it));
}

void PCLViewer::on_OKShowSectionPushButton_clicked()
{
    showTheSelectedItem();
}

void PCLViewer::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_Left)
    {
        int currentIndex = ui->showItComboBox->currentIndex();
        if(currentIndex > 0)
        {
            ui->showItComboBox->setCurrentIndex(currentIndex -1);
            showTheSelectedItem();
        }
    }
    else if(event->key() == Qt::Key_Right)
    {
        int currentIndex = ui->showItComboBox->currentIndex();
        if(currentIndex < ui->showItComboBox->count()-1)
        {
            ui->showItComboBox->setCurrentIndex(currentIndex + 1);
            showTheSelectedItem();
        }
    }
}

void PCLViewer::showTheSelectedItem()
{
    if(ui->showItComboBox->count() <= 0)
    {
        QMessageBox::information(this,"Warning","There is no results");
        return;
    }
    else
    {
        std::string prim,assoc;
        char *tmp = new char[255];
        std::string current = ui->showSectionComboBox->currentText().toStdString();
        if(current == "Segment")
        {
            prim = "segments.csv";
            assoc = "points_segments.csv";
        }
        else if(current == "Generate")
        {
            sprintf(tmp,"candidates_it%d.csv",ui->showItComboBox->currentIndex());
            prim = tmp;
            sprintf(tmp,"points_primitives_it%d.csv",ui->showItComboBox->currentIndex());
            assoc = tmp;
        }
        else if(current == "Generate1")
        {
            sprintf(tmp,"primitives_it%d.bonmin.csv",ui->showItComboBox->currentIndex());
            prim = tmp;
            sprintf(tmp,"points_primitives_it%d.csv",ui->showItComboBox->currentIndex());
            assoc = tmp;
        }
        else if(current == "Solve")
        {
            sprintf(tmp,"candidates_it%d.csv",ui->showItComboBox->currentIndex());
            prim = tmp;
            sprintf(tmp,"points_primitives_it%d.csv",ui->showItComboBox->currentIndex());
            assoc = tmp;
        }
        else if(current == "Represent")
        {
            sprintf(tmp,"representatives_it%d.csv",ui->showItComboBox->currentIndex());
            prim = tmp;
            sprintf(tmp,"points_representatives_it%d.csv",ui->showItComboBox->currentIndex());
            assoc = tmp;
        }
        else if(current == "Merge")
        {
            sprintf(tmp,"primitives_merged_it%d.csv",ui->showItComboBox->currentIndex());
            prim = tmp;
            sprintf(tmp,"points_primitives_it%d.csv",ui->showItComboBox->currentIndex());
            assoc = tmp;
        }

        currentPrimitive = prim;
        currentAssocitive = assoc;
        show3DResults(currentPrimitive,currentAssocitive);
    }
}


void PCLViewer::showLog(std::string dir)
{
    using namespace std;
    fstream in(dir + "log",ios::in);
    string str;
    while(getline(in,str))
    {
        ui->logTextEdit->append(QString::fromStdString(str));
    }
}


void PCLViewer::on_showLogPushButton_clicked()
{
    std::string prefix=cloudFileName.substr(0,cloudFileName.find_last_of("/")+1);
    showLog(prefix);
}
